#include <stdio.h>
#include <time.h>
#include <unistd.h>

typedef unsigned int (*PRT_FILTER_FUNC)(const char func[], unsigned int line, unsigned int filterTime);

extern unsigned int print_filter(const char func[], unsigned int line, unsigned int filterTime);
PRT_FILTER_FUNC errPrtFilter = print_filter;

#define PRT_MAX_PRT_LOC_CNT (32)
unsigned int gPrtLocSum[PRT_MAX_PRT_LOC_CNT] = {0};
unsigned long long gPrtLocTime[PRT_MAX_PRT_LOC_CNT] = {0};
unsigned int gPrtLogIdx = 0;
unsigned int errDebug = 1;

unsigned long long sys_pts_get_ms()
{
	struct timespec tv;
    unsigned long long lasttime = 0;
	/*CLOCK_REALTIME：这种类型的时钟可以反映wall clocktime，用的是绝对时间*/
	/*当系统的时钟源被改变，或者系统管理员重置了系统时间之后，这种类型的时钟可以得到相应的调整*/

	/*CLOCK_MONOTONIC：用的是相对时间，他的时间是通过jiffies值来计算的*/
	/*该时钟不受系统时钟源的影响，只受jiffies值的影响。*/
	
	clock_gettime(CLOCK_MONOTONIC, &tv);
    lasttime = tv.tv_sec * 1000 + tv.tv_nsec/(1000 * 1000);
    return lasttime;
}

unsigned int print_filter(const char func[], unsigned int line, unsigned int filterTime)
{
	unsigned long long curTime = 0, maxTime = 0;
	unsigned int sum = 0;
	unsigned int i = 0;
    // 获取当前时间
	curTime = sys_pts_get_ms();
	//提取特征
	while(func[i])
	{
		sum += func[i];
		i++;
	}
	sum = ((sum & 0x1FFF) << 19) + ((line * i) & 0x7FFFF);
	// 匹配最近一次打印 
	for(i = 0; i < PRT_MAX_PRT_LOC_CNT; i++)
	{
		if(gPrtLocSum[i] == sum && maxTime < gPrtLocTime[i])
		{
			maxTime = gPrtLocTime[i];
		}
	}
	if(curTime > maxTime && (curTime - maxTime) < filterTime)
	{
		return 0; // 短时间内连续打印，需要屏蔽
	}
	gPrtLocSum[gPrtLogIdx] = sum;
	gPrtLocTime[gPrtLogIdx] = curTime;
	gPrtLogIdx = (gPrtLogIdx + 1) % PRT_MAX_PRT_LOC_CNT;
	return 1;
}

#define PRTE(fmt...)   \
do {\
    if (errDebug)  \
    { \
    	if(errPrtFilter && errPrtFilter(__FUNCTION__, __LINE__, 10000)) \
    	{ \
    		printf("[%s][%d]...", __FUNCTION__, __LINE__);\
       		printf(fmt); \
    	} \
    } \
}while(0)

int main(int argc, char *argv[])
{
    int i = 0;
    while(1)
    {
        PRTE("i = %d\n", i);
        printf("i = %d\n", i++);
        i %= 100;
        sleep(1);
    }
    return 0;
}
